﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Xml.Linq;
using xycn.framework.Common;
using xycn.framework.MidwareManagement;
using xycn.framework.PluginManagement;
using xycn.pluginsupport.BaseHelperPlugins;

namespace xycn.framework
{
    public class FrameworkConfig
    {
        public static string errMsg = "";

        static List<string> _hostUrls = new List<string>();
        /// <summary>
        /// 定义服务访问地址，使用类似如下方式进行定义
        /// http://0.0.0.0:3000
        /// https://127.0.0.1:3001
        /// 一个服务可以绑定多个地址
        /// </summary>
        public static List<string> hostUrls { get { return _hostUrls; } }

        static string _apiVersion = "v1.0";
        /// <summary>
        /// api版本信息
        /// </summary>
        public static string apiVersion { get { return _apiVersion; } }

        static string _basePath = "/";
        /// <summary>
        /// 服务基本地址
        /// </summary>
        public static string basePath { get { return _basePath; } }

        #region ====== 跨域策略配置 ======
        static bool _allowAnyOrigin = false;
        /// <summary>
        /// 是否允许所有来源跨域
        /// </summary>
        public static bool allowAnyOrigin { get { return _allowAnyOrigin; } }

        static List<string> _allowOrigins = new List<string>();
        /// <summary>
        /// 定义跨域访问的来源地址
        /// </summary>
        public static List<string> allowOrigins { get { return _allowOrigins; } }

        static bool _allowAnyMethod = false;
        /// <summary>
        /// 是否允许所有的请求方法跨域访问
        /// </summary>
        public static bool allowAnyMethod { get { return _allowAnyMethod; } }

        static List<string> _allowMethods = new List<string>();
        /// <summary>
        /// 允许跨域的请求方法列表
        /// </summary>
        public static List<string> allowMethods { get { return _allowMethods; } }

        static bool _allowAnyHeader = false;
        /// <summary>
        /// 是否允许携带所有的非基本请求头进行跨域访问
        /// </summary>
        public static bool allowAnyHeader { get { return _allowAnyHeader; } }


        static List<string> _allowHeaders = new List<string>();
        /// <summary>
        /// 允许携带的非基本请求头
        /// </summary>
        public static List<string> allowHeaders { get { return _allowHeaders; } }

        static bool _allowCredentials = false;
        /// <summary>
        /// 是否允许跨域访问携带cookie
        /// </summary>
        public static bool allowCredentials { get { return _allowCredentials; } }
        #endregion


        static long _maxResponseBufferSize = 0;
        /// <summary>
        /// 下载文件最大长度，0为无限制
        /// </summary>
        public static long maxResponseBufferSize { get { return _maxResponseBufferSize; } }

        static long _maxRequestBodySize = 0;
        /// <summary>
        /// 上传文件最大长度，0为无限制
        /// </summary>
        public static long maxRequestBodySize { get { return _maxRequestBodySize; } }


        static string _certificatePath = "";
        /// <summary>
        /// api版本信息
        /// </summary>
        public static string certificatePath { get { return _certificatePath; } }

        static X509Certificate2 _certificate = null;
        /// <summary>
        /// X509证书
        /// </summary>
        public static X509Certificate2 certificate { get { return _certificate; } }

        /// <summary>
        /// 当前加载的中间件列表
        /// </summary>
        public static List<MidwareInfo> midwareInfos = new List<MidwareInfo>();

        /// <summary>
        /// 加载配置文件,仅基本框架程序能够调用
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public static int LoadConfiguration(string file)
        {
            int ret = 0;
            pluginsupport.ControllerPlugins.BaseConfiguration.RuntimeDir = Program.RuntimeDir;

            try
            {
                //将XML文件加载进来
                XDocument document = XDocument.Load(file);

                //加载Framework配置
                XElement framework_node = document.Root.Element("FrameworkConfig");

                #region 优先加载日志记录插件，以便记录启动日志
                if (document.Root.Element("LogPlugins") != null)
                {
                    XElement logconfig_node =
                        document.Root.Element("LogPlugins");

                    string err_msg;
                    List<IPluginFactory.IPluginFactory> factories = null;
                    if (LoadHelperPlugins(logconfig_node, out factories, out err_msg) < 0)
                    {
                        LogHelper.Error(err_msg, Program.isDebugMode);
                        ret = -1;
                    }
                    else
                    {
                        if (factories.Count > 0)
                            LogHelper.Init(factories[0]);
                    }
                }
                #endregion

                #region 加载配置文件
                LogHelper.Info("Step 1:加载配置文件（配置文件为与服务程序同名的xml文件）......",
                        Program.isDebugMode);

                LogHelper.Info("Step 1 OK:配置文件加载完成。",
                       Program.isDebugMode);

                LogHelper.Info("Step 2:加载框架基本配置......",
                        Program.isDebugMode);

                if (framework_node.Element("APIVersion") != null)
                    _apiVersion = framework_node.Element("APIVersion").Value;
                if (framework_node.Element("BasePath") != null)
                    _basePath = framework_node.Element("BasePath").Value;
                #endregion

                #region 加载https证书  跨域策略   加载跨域允许来源
                //加载https证书
                if (framework_node.Element("HttpsCertificate") != null)
                {
                    _certificatePath = framework_node.Element("HttpsCertificate").Value;
                    //加载指定证书
                    if (certificatePath != null && certificatePath != "")
                    {
                        try
                        {
                            //如果存在证书则加载证书
                            _certificate = new X509Certificate2(certificatePath);
                        }
                        catch (Exception ex)
                        {
                            LogHelper.Warn("配置文件中指定的证书文件不存在，不会启动HTTPS服务",
                                Program.isDebugMode);
                        }
                    }
                }

                //设置最大回应长度，0为不限制
                if (framework_node.Element("MaxResponseBufferSize") != null)
                    _maxResponseBufferSize =
                        Convert.ToInt64(framework_node.Element("MaxResponseBufferSize").Value);

                //设置最大请求长度，0为不限制
                if (framework_node.Element("MaxRequestBodySize") != null)
                    _maxRequestBodySize =
                        Convert.ToInt64(framework_node.Element("MaxRequestBodySize").Value);

                //跨域策略
                XElement cors_policies =
                    framework_node.Element("CorsPolicies");

                //加载跨域允许来源
                IEnumerable<XElement> allow_orgins =
                    cors_policies.Element("AllowOrigins").Elements();
                foreach (XElement item in allow_orgins)
                {
                    if (item.Value == "*")
                    {
                        _allowAnyOrigin = true;
                        break;
                    }
                    _allowOrigins.Add(item.Value);
                }
                #endregion

                #region 加载跨域允许方法
                IEnumerable<XElement> allow_methods =
                   cors_policies.Element("AllowMethods").Elements();
                foreach (XElement item in allow_methods)
                {
                    if (item.Value == "*")
                    {
                        _allowAnyMethod = true;
                        break;
                    }
                    _allowMethods.Add(item.Value);
                }
                #endregion

                #region 加载跨域允许携带的非基本请求头
                IEnumerable<XElement> allow_headers =
                   cors_policies.Element("AllowHeaders").Elements();
                foreach (XElement item in allow_headers)
                {
                    if (item.Value == "*")
                    {
                        _allowAnyHeader = true;
                        break;
                    }
                    _allowHeaders.Add(item.Value);
                }
                #endregion

                #region 加载跨域是否允许携带cookies
                XElement allow_credentials =
                   cors_policies.Element("AllowCredentials");
                if (_allowAnyOrigin || allow_credentials == null ||
                    allow_credentials.Value != "true")
                {
                    _allowCredentials = false;
                }
                else
                {
                    _allowCredentials = true;
                }
                #endregion

                #region 加载启动服务的地址
                IEnumerable<XElement> urls =
                    framework_node.Element("HostUrls").Elements();
                foreach (XElement item in urls)
                {
                    _hostUrls.Add(item.Value);
                }

                LogHelper.Info("Step 2 OK:框架基本配置加载完成",
                        Program.isDebugMode);

                LogHelper.Info("Step 3:创建Controller插件调用器......",
                        Program.isDebugMode);
                #endregion

                #region 加载Controller插件
                //加载Controller插件
                if (document.Root.Element("ControllerPlugins") != null)
                {
                    XElement controllerconfig_node =
                        document.Root.Element("ControllerPlugins");
                    string err_msg;
                    if (LoadControllerPlugins(controllerconfig_node, out err_msg) < 0)
                    {
                        LogHelper.Error(err_msg, Program.isDebugMode);
                        ret = -1;
                    }

                    pluginsupport.ControllerPlugins.ControllerConfigure.RuntimeDir = Program.RuntimeDir;
                    pluginsupport.ControllerPlugins.ControllerConfigure controllerConfiguration =
                        new pluginsupport.ControllerPlugins.ControllerConfigure(
                            controllerconfig_node);
                }
                LogHelper.Info("Step 3 OK:Controller插件调用器创建完成",
                       Program.isDebugMode);
                #endregion

                #region 加载Asp.NetCore中间件插件
                LogHelper.Info("Step 4:加载指定Asp.Net 中间件插件.....",
                       Program.isDebugMode);
                if (document.Root.Element("Asp.netMidwarePlugins") != null)
                {
                    XElement midwareconfig_node =
                        document.Root.Element("Asp.netMidwarePlugins");
                    string err_msg;
                    if (LoadMidwarePlugins(midwareconfig_node, out err_msg) < 0)
                    {
                        LogHelper.Error(err_msg, Program.isDebugMode);
                        ret = -1;
                    }

                    pluginsupport.AspNetCorePlugins.MidwareConfigure.RuntimeDir = Program.RuntimeDir;
                    pluginsupport.AspNetCorePlugins.MidwareConfigure controllerConfiguration =
                        new pluginsupport.AspNetCorePlugins.MidwareConfigure(
                            midwareconfig_node);
                }
                LogHelper.Info("Step 4 OK:中间件插件创建完成",
                       Program.isDebugMode);
                #endregion

                #region 加载数据库访问接口实例库
                LogHelper.Info("Step 5:加载指定ORM插件.....",
                       Program.isDebugMode);
                if (document.Root.Element("ORMPlugins") != null)
                {
                    XElement dbconfig_node =
                        document.Root.Element("ORMPlugins");
                    List<IPluginFactory.IPluginFactory> factories = null;

                    string err_msg;
                    if (LoadHelperPlugins(dbconfig_node, out factories, out err_msg) < 0)
                    {
                        LogHelper.Error(err_msg, Program.isDebugMode);
                        ret = -1;
                    }
                    else
                    {
                        foreach (IPluginFactory.IPluginFactory factroy in factories)
                        {
                            DbHelper.Init(factroy.pluginName, factroy);
                        }
                    }
                }
                LogHelper.Info("Step 5 OK:ORM插件创建完成",
                       Program.isDebugMode);
                #endregion

                #region 加载文件访问接口实例库
                LogHelper.Info("Step 6:加载指定其他辅助类插件.....",
                      Program.isDebugMode);
                if (document.Root.Element("FileHelperPlugins") != null)
                {
                    XElement fileconfig_node =
                        document.Root.Element("FileHelperPlugins");

                    string err_msg;
                    List<IPluginFactory.IPluginFactory> factories = null;
                    if (LoadHelperPlugins(fileconfig_node, out factories, out err_msg) < 0)
                    {
                        LogHelper.Error(err_msg, Program.isDebugMode);
                        ret = -1;
                    }
                    else
                    {
                        foreach (IPluginFactory.IPluginFactory factroy in factories)
                        {

                            FileHelper.Init(factroy.pluginName, factroy);
                        }
                    }
                }
                LogHelper.Info("Step 6 OK:辅助类插件创建完成",
                       Program.isDebugMode);
                #endregion

                #region 加载权限认证接口实例库
                LogHelper.Info("Step 7:加载Auth权限插件.....",
                      Program.isDebugMode);
                if (document.Root.Element("AuthHelperPlugins") != null)
                {
                    XElement authconfig_node =
                       document.Root.Element("AuthHelperPlugins");

                    string err_msg;
                    List<IPluginFactory.IPluginFactory> factories = null;
                    if (LoadHelperPlugins(authconfig_node, out factories, out err_msg) < 0)
                    {
                        LogHelper.Error(err_msg, Program.isDebugMode);
                        ret = -1;
                    }
                    else
                    {
                        if (factories.Count > 0)
                            AuthHelper.Init(factories[0]);
                    }
                    LogHelper.Info("Step 7 OK:Auth权限插件创建完成",
                       Program.isDebugMode);
                }
                else
                {
                    LogHelper.Info("Step 7 OK:Auth权限未配置，不启用权限验证",
                      Program.isDebugMode);
                }

                #endregion


                #region 加载缓存插件实例
                LogHelper.Info("Step 7:加载缓存插件.....",
                      Program.isDebugMode);
                if (document.Root.Element("RedisPlugins") != null)
                {
                    XElement cache_node =
                       document.Root.Element("RedisPlugins");

                    string err_msg;
                    List<IPluginFactory.IPluginFactory> factories = null;
                    if (LoadHelperPlugins(cache_node, out factories, out err_msg) < 0)
                    {
                        LogHelper.Error(err_msg, Program.isDebugMode);
                        ret = -1;
                    }
                    else
                    {
                        if (factories.Count > 0)
                            DataCacheHelper.Init(factories[0]);
                    }
                    LogHelper.Info("Step 7 OK:加载缓存插件创建完成",
                       Program.isDebugMode);
                }
                else
                {
                    LogHelper.Info("Step 7 OK:缓存插件未配置，不启用框架缓存",
                      Program.isDebugMode);
                }

                #endregion

            }
            catch (Exception ex)
            {
                errMsg = errMsg + "根据配置文件\"" + file + "\"进行初始化时，出错了。错误信息：" + ex.Message;
                ret = -1;
            }

            return ret;
        }

        #region ====== 加载控制器插件 ======
        /// <summary>
        /// 加载控制器插件
        /// </summary>
        /// <param name="controllerpath_node"></param>
        /// <returns></returns>
        private static int LoadControllerPlugins(XElement controllerconfig_node, out string err_msg)
        {
            int ret = 0;

            err_msg = "";

            //获取controller插件位置
            IEnumerable<XElement> controllers =
                controllerconfig_node.Elements();

            //遍历控制器插件配置
            foreach (XElement item in controllers)
            {
                XAttribute controller_attr = item.Attribute("lib");
                if (controller_attr == null)
                {
                    LogHelper.Error(">>>>>加载" + item.ToString() + "存在错误!",
                        Program.isDebugMode);
                    err_msg = "Controller配置项存在问题：未找到lib属性，无法定位Controller插件存放路径...";
                    ret = -1;
                    continue;
                }
                string controller_path = controller_attr.Value;

                controller_path =
                    MultiOSSupportExtension.CalculateAbsoluteDir(Program.RuntimeDir,
                    controller_path);

                LogHelper.Info(">>>>>加载\"" + controller_path + "\"...",
                        Program.isDebugMode);

                if (ControllerManagement.ControllerManager.CreateControllerInvoker
                    (controller_path) < 0)
                {
                    err_msg = "在创建控制器调用器时，存在以下问题：\r\n" +
                        ControllerManagement.ControllerManager.errMsg;
                    ret = -1;
                }

                LogHelper.Info(">>>>>加载完成",
                        Program.isDebugMode);

            }
            return ret;
        }
        #endregion

        #region ====== 加载Asp.NetCore中间件插件 ======
        /// <summary>
        /// 根据配置文件中配置的某类Helper插件列表进行加载
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="config_node"></param>
        /// <returns></returns>
        private static int LoadMidwarePlugins(XElement plugin_config_node, 
            out string err_msg)
        {
            int ret = 0;
            err_msg = "";

            //获取controller插件位置
            IEnumerable<XElement> plugin_interfaces =
                plugin_config_node.Elements();

            //遍历控制器插件配置
            foreach (XElement item in plugin_interfaces)
            {
                XAttribute lib_attr = item.Attribute("lib");
                if (lib_attr == null)
                {
                    err_msg = "插件配置项存在问题：未找到lib属性，无法定位插件存放路径...";
                    ret = -1;
                    continue;
                }
                string plugin_path = lib_attr.Value;

                LogHelper.Info(">>>>> 加载插件:" + plugin_path,
                       Program.isDebugMode);

                plugin_path =
                    MultiOSSupportExtension.CalculateAbsoluteDir(Program.RuntimeDir,
                    plugin_path);

                //加载中间件插件接口
                List<MidwareInfo> mid_ware;
                if (MidwareLoader.LoadMidwares(plugin_path, out mid_ware) < 0)
                {
                    err_msg = "在加载中间件时，存在以下问题：\r\n" +
                        MidwareLoader.errMsg;
                    ret = -1;
                }

                if (mid_ware != null)
                    midwareInfos.AddRange(mid_ware);

                LogHelper.Info(">>>>>加载完成",
                        Program.isDebugMode);
            }
            return ret;
        }
        #endregion

        #region ====== 加载辅助工具插件 ======
        /// <summary>
        /// 根据配置文件中配置的某类Helper插件列表进行加载
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="config_node"></param>
        /// <returns></returns>
        private static int LoadHelperPlugins(XElement plugin_config_node,
            out List<IPluginFactory.IPluginFactory> factories, out string err_msg)
        {
            int ret = 0;
            factories =
                new List<IPluginFactory.IPluginFactory>();
            err_msg = "";


            //获取controller插件位置
            IEnumerable <XElement> plugin_interfaces =
                plugin_config_node.Elements();

            //遍历控制器插件配置
            foreach (XElement item in plugin_interfaces)
            {
                XAttribute lib_attr = item.Attribute("lib");
                if (lib_attr == null)
                {
                    err_msg = "插件配置项存在问题：未找到lib属性，无法定位插件存放路径...";
                    ret = -1;
                    continue;
                }
                string plugin_path = lib_attr.Value;

                LogHelper.Info(">>>>> 加载插件:" + plugin_path,
                       Program.isDebugMode);

                XAttribute name_attr = item.Attribute("name");
                if (name_attr == null)
                {
                    err_msg = "插件配置项存在问题：未找到name属性，无法定位插件存放路径...";
                    ret = -1;
                    continue;
                }
                string plugin_name = name_attr.Value;

                plugin_path =
                    MultiOSSupportExtension.CalculateAbsoluteDir(Program.RuntimeDir,
                    plugin_path);

                //加载ORM插件接口
                Assembly plugin_assembly = GlobalContext.LoadPlugin(plugin_path);

                IPluginFactory.IPluginFactory plugin_factory = null;

                Type IType = typeof(IPluginFactory.IPluginFactory);
                Type[] types = plugin_assembly.GetTypes();

                foreach (Type type in types)
                {
                    if (IType != type.BaseType)
                        continue;

                    plugin_factory =
                        (IPluginFactory.IPluginFactory)Activator.CreateInstance(type);

                    if (plugin_factory == null)
                    {
                        err_msg = "ORM插件配置项存在问题：未能映射ORM插件" +
                            plugin_name + "类工厂...";
                        ret = -1;
                        break;
                    }
                    plugin_factory.pluginConfig = item;
                    break;
                }

                plugin_factory.pluginName = plugin_name;

                factories.Add(plugin_factory);
                LogHelper.Info("完成",
                       Program.isDebugMode);
            }
            return ret;
        }
        #endregion
    }
}
